use axum::{Json, Router};
use axum::http::StatusCode;
use axum::routing::{get, post};
use serde::{Deserialize, Serialize};

use crate::constants::{APP_CONFIG, FOO};

mod app_config;
mod constants;
mod init;

#[tokio::main]
async fn main() {
    let host = APP_CONFIG.server.host.as_str();
    let port = APP_CONFIG.server.port;

    let app = Router::new()
        .route("/", get(root))
        .route("/hello", get(hello))
        // `POST /users` goes to `create_user`
        .route("/users", post(create_user));

    let listener = tokio::net::TcpListener::bind(format!("{}:{}", host, port)).await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

// basic handler that responds with a static string
async fn root() -> &'static str {
    "Hello, World!"
}

async fn hello() -> (StatusCode, Json<Hello>) {
    let hello = Hello {
        message: "Hello World!".to_string(),
        // foo: APP_CONFIG.db.db_type.to_string(),
        foo: FOO.to_string(),
    };

    (StatusCode::OK, Json(hello))
}

async fn create_user(
    // this argument tells axum to parse the request body
    // as JSON into a `CreateUser` type
    Json(payload): Json<CreateUser>,
) -> (StatusCode, Json<User>) {
    // insert your application logic here
    let user = User {
        id: 1337,
        username: payload.username,
    };

    // this will be converted into a JSON response
    // with a status code of `201 Created`
    (StatusCode::CREATED, Json(user))
}

// the input to our `create_user` handler
#[derive(Deserialize)]
struct CreateUser {
    username: String,
}

// the output to our `create_user` handler
#[derive(Serialize)]
struct User {
    id: u64,
    username: String,
}

#[derive(Serialize)]
struct Hello {
    message: String,
    foo: String,
}
